package dolf.objects;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Stroke;
import dolf.objects.WorldObject;


public class LineObject extends WorldObject implements java.io.Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Point end;
	private final int LINE_WIDTH = 2;
	private CircleObject p1;
	private CircleObject p2;
	private Vector direction;
	private double distP1P2;
	public LineObject(Point start, Point end){
		super(false);
		this.position = start;
		this.end = end;
		p1 = new CircleObject(this.getPosition(), this.LINE_WIDTH/2 ,false);
		p2 = new CircleObject(this.getEnd(), this.LINE_WIDTH/2 ,false);
		distP1P2 = p1.getPosition().getDist(p2.getPosition());
		direction = new Vector(end.getX()-this.position.getX(),this.end.getY()-this.position.getY());
	}
	
	public void setEnd(Point point){
		this.end = point;		
	}
	public Point getEnd(){
		return this.end;
	}
	public int getLindWidth(){
		return this.LINE_WIDTH;
	}
	public void paint(Graphics2D g){
		int r = this.getCircleP1().getRadius();
		g.drawOval(this.getPosition().getIntX()-r,this.getPosition().getIntY()-r,r*2,r*2);
		g.drawOval(this.getEnd().getIntX()-r,this.getEnd().getIntY()-r,r*2,r*2);
		Stroke tmp = g.getStroke();
		//Stroke foo = new BasicStroke(L)
		g.setStroke(new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL ) );
		//g.setStroke(new BasicStroke(LINE_WIDTH));
		g.drawLine(this.position.getIntX(),this.position.getIntY(), end.getIntX(), end.getIntY());
		
		g.setStroke(tmp);
	}

	public Vector getNormVec(){
		return this.getDirection().getNormVec().getNormed();		
	}
	public Vector getDirection(){
		return this.direction; 
	}
	public CircleObject getCircleP1(){
		return this.p1;
	}
	public CircleObject getCircleP2(){
		return this.p2;
	}
	public double getDistP1P2(){
		return this.distP1P2;
	}
	public Point getIntersection(Point point, Vector direction){
		/*
		 	( this.getDirektion 	direction) (x)		(point.x - 	this.position.x	)  	
		 	(								 ) ( )	=	(							)
		 	( this.getDirektion 	direction) (y)		(point.y -	this.position.y	)
		 */
		 
		/*double det = this.getDirection().getX()*direction.getY() - this.getDirection().getY()*direction.getX(); 
		if(det == 0){ // Fall Parallel oder Identisch
			System.err.println("Parallel oder Identische Gerade");
			return null; // es exisitiert kein schnittpunkt
		} else {
			// Berechntet Schnittpunkt s;
			double x = ((point.getX() - this.getPosition().getX()) * direction.getY() - (point.getY() - this.getPosition().getY()) * direction.getX()) / det;
			Point S = this.getPosition().add(this.getDirection().multS(x));
			double d1 = S.getDist(this.getCircleP1().getPosition());
			double d2 = S.getDist(this.getCircleP2().getPosition());
			if(Math.abs(d1+d2-this.distP1P2)>1.0E-13){
				return null;
			}
			return S; 
		}*/
		return Intersect.LineXStraight(this, point, direction);
	}
	public boolean newMotion(WorldObject object){
		if(object instanceof CircleObject){
			CircleObject obj = (CircleObject) object;
			//double a,b=obj.getRadius();
			// sonderfall ball trifft auf einen Eckpunkt der Linie
			
			CircleObject c1 = this.getCircleP1();
			double d=obj.kollCircle(c1);
			if(Math.abs(d) < 1.0E-13){
				System.out.println("abprall kugel");
				CircleKoll(this.getPosition(), obj);
				return true;
			}
			if(d>0){
				System.out.println(d);
			}
			CircleObject c2 = this.getCircleP2();
			d=obj.kollCircle(c2);
			if(Math.abs(d) < 1.0E-13){
				System.out.println("abprall kugel");
				CircleKoll(this.getEnd(), obj);
				return true;
			}
			if(d>0){
				System.out.println(d);
			}
		
			
			/*if((this.getEnd().getDist(obj.getPosition()))<=obj.getRadius() ||(this.getPosition().getDist(obj.getPosition()))<=obj.getRadius()){
				//spiegelung des bewegungsvektors an der normalen der gerade
				double length = (obj.getMotion().multX(this.getDirection().getNormVec())) / (this.getDirection().getNormVec().getX()*this.getDirection().getNormVec().getX() + this.getDirection().getNormVec().getY()*this.getDirection().getNormVec().getY());
				Vector tmp = this.getDirection().getNormVec().multS(length);
				obj.setMotion((obj.getMotion().add(tmp.sub(obj.getMotion()).multS(2))));//.setLength(obj.getMaxSpeed()));
			return true;
			} else {*/
				/*spiegelung des bewegungsvektors an der gerade*/
			double length = (obj.getMotion().multX(this.getDirection())) / (this.getDirection().multX(this.getDirection()));
			Vector tmp = this.getDirection().multS(length);
			obj.setMotion(new Vector(obj.getMotion().getX() + 2*(tmp.getX()-obj.getMotion().getX()), obj.getMotion().getY()+ 2*(tmp.getY()-obj.getMotion().getY()))); 
			
		}
		return true;
	}
	//kollision with p1 or p2
	private void CircleKoll(Point koll,CircleObject obj){
		double tmp  = obj.getMotion().getLength();
	    Vector impact;
	    impact = obj.getMotion().multS(-1);  
	    Vector impulse = koll.sub(obj.getPosition()).getNormed();	
	    double ImpactSpeed = impact.multX(impulse); 
	    impulse = impulse.multS(Math.sqrt(Math.abs(ImpactSpeed) *20*  obj.getMass()));
		obj.setMotion(obj.getMotion().sub(impulse.multS(1/obj.getMass())));
		if(obj instanceof Ball){
			((Ball)obj).addCollition(this);
		}
		obj.setMotion(obj.getMotion().setLength(tmp));
	}
	// intersection with a circle middlepoint pos and radius rad
	// p1 and p2 are ignored
	public Point[] CircleIntersect(Point pos, int rad){
		
		return Intersect.CircleXLine(pos,rad, this);
		/*Point[] erg;
		Point t = this.getPosition().sub(pos);
		double c = (t.getX()*t.getX()+t.getY()*t.getY()-rad*rad);
		double b = 2*this.getDirection().getX()*t.getX()+ 2*this.getDirection().getY()*t.getY();
		double a = this.getDirection().getX()*this.getDirection().getX()+this.getDirection().getY()*this.getDirection().getY();
		double w = b*b - 4 * a * c;
		if(w<0){
			return null;
		} else {
			if(w==0){
				erg = new Point[1];
				double k = -b/(2*a);
				erg[0] = new Point(this.getPosition().getX()+k*this.getDirection().getX(),this.getPosition().getY()+k*this.getDirection().getY());			
			} else {
				erg = new Point[2];
				double k1 = (-b+Math.sqrt(w))/(2*a);
				double k2 = (-b-Math.sqrt(w))/(2*a);
				erg[0] = new Point(this.getPosition().getX()+k1*this.getDirection().getX(),this.getPosition().getY()+k1*this.getDirection().getY());			
				erg[1] = new Point(this.getPosition().getX()+k2*this.getDirection().getX(),this.getPosition().getY()+k2*this.getDirection().getY());			
			}
			int z = 0;
			for(int i = 0; i < erg.length; i++){
				System.out.println("P length "+erg.length);
				double d1 = erg[i].getDist(this.getPosition());
				double d2 = erg[i].getDist(this.getEnd());
				if(d1+d2<=this.distP1P2){
					z += i + 1;
				}
			}
			switch(z){
			case 0:
				erg = null;
				break;
			case 1:
				Point tmp = erg[0];
				erg = new Point[1];
				erg[0] = tmp;
				break;
			case 2:
				tmp = erg[1];
				erg = new Point[1];
				erg[0] = tmp;
			}
			return erg;
		}*/
	}	
	/* true if the Result p of an Intersection is Between the Bounds of this */
	public boolean IntersectBetweenBounds(Point p){
		if(p == null){
			return false;
		}
		double distP1P2 = this.getDistP1P2();
		double d1 = p.getDist(this.getPosition());
		double d2 = p.getDist(this.getEnd());
		if(Math.abs(d1+d2-distP1P2)>1.0E-13){
			return false;
		}
		return true;
	}
}
